package com.aliyun.frontframework;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Calendar;

import android.content.Context;
import android.content.Intent;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OnInfoListener;
import android.os.Environment;
import android.os.PowerManager;
import android.os.StatFs;
import android.util.Log;

public class RecordWorker implements OnErrorListener, OnInfoListener {
    private static final String TAG = "RecordWorker";

    private Camera mCamera;
    public static final int MSG_NEW = 1;
    private PowerManager mPM = null;
    private PowerManager.WakeLock mWL = null;
    private boolean mIsCollision = false;
    private Context mCtx = null;
    private Callback mCM = null;

    public void setCollision() {
        mIsCollision = true;
    }

    /**
     * DVR的文件夹
     */
    private String mDVRPath = "";

    public RecordWorker(Camera camera, Context ctx, Callback cm) {
        this.mCamera = camera;
        video = new DVRVideoModel();
        mCtx = ctx;
        mCM = cm;

        mPM = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
        mWL = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                "com.aliyun.dvrapp");
    }

    private void setParam(DVRRecordParamModel param) {
        this.param = param;
        video.cameraId = param.cameraId;
        video.duration = param.duration;
    }

    /**
     * 录制视频的对象
     */
    private MediaRecorder mediaRecorder;

    private DVRRecordParamModel param;

    /**
     * video对象
     */
    private DVRVideoModel video;

    public boolean isRecording;

    public static String getNowTimeName(int cameraId) {
        final Calendar mCalendar = Calendar.getInstance();
        int mYear = mCalendar.get(Calendar.YEAR);
        int mHour = mCalendar.get(Calendar.HOUR_OF_DAY);
        int mMinuts = mCalendar.get(Calendar.MINUTE);
        int mDay = mCalendar.get(Calendar.DAY_OF_MONTH);
        int mMoth = (mCalendar.get(Calendar.MONTH) + 1);
        int mSec = (mCalendar.get(Calendar.SECOND));
        return "VIDfront_" + mYear + String.format("%02d", mMoth)
                + String.format("%02d", mDay) + "_"
                + String.format("%02d", mHour) + String.format("%02d", mMinuts)
                + String.format("%02d", mSec) + ".mp4";
    }

    public static String generateSdPath() {
        final Calendar mCalendar = Calendar.getInstance();
        int mYear = mCalendar.get(Calendar.YEAR);
        int mDay = mCalendar.get(Calendar.DAY_OF_MONTH);
        int mMoth = (mCalendar.get(Calendar.MONTH) + 1);
        // TODO 目录名字修改
        File pathThis = new File(Environment.getExternalStorageDirectory().getPath() + "/" + "DVR" + File.separator
                + mYear + String.format("%02d", mMoth)
                + String.format("%02d", mDay));
        Log.w(TAG, "DEADBEAF pathThis");
        boolean isO = false;
        if (!pathThis.exists() || !pathThis.isDirectory()) {
            isO = pathThis.mkdirs();
        }
        Log.w(TAG, "generateSdPath  " + pathThis.getAbsolutePath() + " " + isO);
        return pathThis.getAbsolutePath();
    }

    @SuppressWarnings("deprecation")
    private void setRecordParams() {
        // 1. init
        mediaRecorder = new MediaRecorder();
        mCamera.unlock();
        mediaRecorder.setCamera(mCamera);

        mediaRecorder.setOnErrorListener(this);
        mediaRecorder.setOnInfoListener(this);
        // 2. init source
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
        if (param.isSound == 1)
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);

        // Following code does the same as getting a CamcorderProfile (but
        // customizable)
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

        CamcorderProfile camPro = CamcorderProfile
                .get(param.cameraId, param._p); // CamcorderProfile.QUALITY_720P
        // camera preview size，should to change to our need size.
        // Video Settings
        if (param._p == CamcorderProfile.QUALITY_1080P) {
            param.width = 1920;
            param.height = 1088;
        } else {
            param.width = 1280;
            param.height = 720;
        }
        mediaRecorder.setVideoSize(param.width, param.height); // TODO no effect
        mediaRecorder.setVideoFrameRate(camPro.videoFrameRate);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setVideoEncodingBitRate(camPro.videoBitRate / 4); // set
                                                                        // 1/4
                                                                        // of
                                                                        // default
                                                                        // value
        // Audio Settings
        if (param.isSound == 1) {
            mediaRecorder.setAudioChannels(camPro.audioChannels);
            // mediaRecorder.setAudioSamplingRate(camPro.audioSampleRate);
            mediaRecorder.setAudioSamplingRate(16000);
            mediaRecorder.setAudioEncoder(camPro.audioCodec);
            mediaRecorder.setAudioEncodingBitRate(camPro.audioBitRate);
        }
        // 第4步:指定输出文件

        video.name = getNowTimeName(video.cameraId);
        mDVRPath = generateSdPath();
        File f = new File(mDVRPath);
        String path = f.getParent();

        String tempName = path + File.separator + video.name;
        Log.e("DVR", "DEADBEAF dvr temp = " + tempName);

        mediaRecorder.setMaxDuration(video.duration);
        // mediaRecorder.setMaxDuration(30000/*video.duration*/);

        video.path = tempName;
        mediaRecorder.setOutputFile(video.path);
    }

    private Thread mUpdateTimeThread;

    private void startUpdateTimeThread() {
        if (mUpdateTimeThread != null) {
            Log.d(TAG, "startThread..not null..");
            if (mUpdateTimeThread.isAlive()) {
                Log.d(TAG, "startThread..no need..");
                return;
            }
        }
        Log.d(TAG, "startThread..new..");
        mUpdateTimeThread = new Thread(updateRunnable);
        startThread(mUpdateTimeThread);
    }

    private void stopUpdateTimeThread() {
        stopThread(mUpdateTimeThread);
    }

    private void startThread(Thread th) {
        if (!th.isAlive()) {
            Log.d(TAG, "startThread..realy..");
            th.start();
        }
    }

    private void stopThread(Thread th) {
        Log.d(TAG, "stopThread....");
        if (th != null && !th.isInterrupted()) {
            Log.d(TAG, "stopThread..realy..");
            th.interrupt();
        }
    }

    private Runnable updateRunnable = new Runnable() {
        long timeSec = 0;

        @Override
        public void run() {
            while (true) {
                Log.i(TAG, "updateTimeRunnable ... " + timeSec);
                mCM.onRecordTimeUpdate(timeSec++);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    Log.w(TAG, "catched stop!!!");
                    timeSec = 0;
                    // put here is really stopped
                    // 如此ushell就不会额外再刷新一次录制时间了。
                    mCM.onStatusChanged(Callback.STATUS_NOT_RECORD);
                    break; // ***********************
                }
            }
        }
    };

    public void setCamera(Camera camera) {
        mCamera = camera;
    }

    public void stopRecord() {
        if (mediaRecorder == null) {
            return;
        }
        // 停止录像
        mediaRecorder.setOnErrorListener(null);

        synchronized (RecordWorker.this) {
            try {
                mediaRecorder.stop();
                // 释放资源
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                mediaRecorder.release();
                mCM.onRecordTimeUpdate(-1);
                mediaRecorder = null;
                isRecording = false;
            }

            if (mCamera != null) {
                mCamera.lock();
            }
        }
        if (mWL.isHeld()) {
            mWL.release();
            Log.d(TAG, "mWL released....");
        } // TODO 在这里释放锁，可能太早了。其他的操作可能没完成。
        stopUpdateTimeThread();
        Log.d(TAG, "stopUpdateTimeThread.stopRecord...");
    }

    public void startRecord(DVRRecordParamModel param) {
        boolean ok = true;
        setParam(param);
        synchronized (RecordWorker.this) {
            try {
                // 开始录制
                setRecordParams();
                mediaRecorder.prepare();
                mediaRecorder.start();
            } catch (Exception e) {
                ok= false;
                e.printStackTrace();
                mCM.onStatusChanged(Callback.STATUS_START_RECORD_ERR);
                if (mediaRecorder != null)
                    mediaRecorder.release();
                mediaRecorder = null;
            }
        }
        if (ok) {
            isRecording = true;// 放在这里，表示肯定已经开启
            if (!mWL.isHeld())
                mWL.acquire();
            startUpdateTimeThread();
            mCM.onStatusChanged(Callback.STATUS_RECORDING);
        }
    }

    @Override
    public void onError(MediaRecorder mr, int what, int extra) {
        // TODO 应该要处理一下
        Log.e(TAG, "onError...Maybe I should restart this thread again!");
        try {
            if (mr != null)
                mr.reset();
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        mCM.onStatusChanged(Callback.STATUS_START_RECORD_ERR);
    }

    @Override
    public void onInfo(MediaRecorder mr, int what, int extra) {
        Log.d(TAG, "DEADBEAF [onInfo] what = " + what + "   extra = " + extra);
        switch (what) {
        case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED:
            Log.d(TAG, "DEADBEAF [onInfo] what = " + what + "   extra = "
                    + extra);
            mCM.onStatusChanged(Callback.STATUS_RECORD_EACH);
            break;
        default:
            break;
        }
    }

    public interface Callback {
        public static final int STATUS_NOT_RECORD = 0;
        public static final int STATUS_RECORDING = 1;
        public static final int STATUS_START_RECORD_ERR = -1;
        public static final int STATUS_RECORD_EACH = 2;
        void onStatusChanged(int status);
        void onRecordTimeUpdate(long time);
    }
}
